package main

import (
	"fmt"
	"strconv"
	"sync"
	"time"
)

type numberBucket struct {
	Value float64
}
type Number struct {
	Buckets map[int64]*numberBucket
	Mutex   *sync.RWMutex
}

func (r Number) getCurrentBucket() *numberBucket {
	now := time.Now().Unix()

	var bucket *numberBucket
	var ok bool

	if bucket, ok = r.Buckets[now]; !ok {
		bucket = &numberBucket{}
		r.Buckets[now] = bucket
	}

	return bucket
}

func (r Number) removeOldBuckets() {
	now := time.Now().Unix() - 10
	for key := range r.Buckets {
		if key <= now {
			delete(r.Buckets, key)
		}
	}
}

func (r Number) Increment(i float64) {
	if i == 0 {
		return
	}

	r.Mutex.Lock()
	defer r.Mutex.Unlock()

	bucket := r.getCurrentBucket()
	bucket.Value += i

	r.removeOldBuckets()
}

func main() {
	n := &Number{
		Buckets: make(map[int64]*numberBucket),
		Mutex:   &sync.RWMutex{},
	}

	for _, x := range []float64{0, 0.3, 0.9, 8, 30.8, 1, 9, 11, 19, 8, 7, 2.2, 9.9, 8.7, 0.9, 8, 30.8, 1, 9, 11} {
		n.Increment(x)

		a := ""
		for _, v := range n.Buckets {
			if a == "" {
				a = a + strconv.FormatFloat(v.Value, 'f', -1, 32)
			} else {
				a = a + "," + strconv.FormatFloat(v.Value, 'f', -1, 32)
			}
		}

		fmt.Println("[" + a + "]")

		time.Sleep(1 * time.Second)
	}
}
